<?php
/**
 * @version $Id: jmethodlister.php 31 2009-06-29 23:20:28Z der.el.kuku $
 *
 * @description scans the directory /libraries/joomla/* and lists all the foud methods whith path and line numbers
 *
 * This file must be placed in joomla root directory.
 * It then scans the directories under /libraries/joomla/ and writes the output to a text file called
 * jmethodlist_JVERSION_.txt
 */
error_reporting(E_ALL);

define( 'DS', DIRECTORY_SEPARATOR );
define( 'BR', '<br />');
define( 'NL', "\n");
$basePath = dirname(__FILE__).DS.'libraries'.DS.'joomla';

define('JPATH_SITE', '');
define('JPATH_ROOT', '');
define('_JEXEC', '');

define('JPATH_BASE', '');

define('JPATH_LIBRARIES', dirname(__FILE__).DS.'libraries');

include_once JPATH_LIBRARIES.DS.'joomla'.DS.'base'.DS.'object.php';
include_once JPATH_LIBRARIES.DS.'joomla'.DS.'base'.DS.'observer.php';
include_once JPATH_LIBRARIES.DS.'joomla'.DS.'base'.DS.'observable.php';
include_once JPATH_LIBRARIES.DS.'joomla'.DS.'event'.DS.'event.php';
include_once JPATH_LIBRARIES.DS.'joomla'.DS.'document'.DS.'renderer.php';
include_once JPATH_LIBRARIES.DS.'joomla'.DS.'registry'.DS.'registry.php';
include_once JPATH_LIBRARIES.DS.'joomla'.DS.'version.php';
include_once JPATH_LIBRARIES.DS.'joomla'.DS.'environment'.DS.'request.php';

include_once JPATH_LIBRARIES.DS.'phpmailer'.DS.'phpmailer.php';

include_once JPATH_LIBRARIES.DS.'pattemplate'.DS.'patTemplate'.DS.'Module.php';
include_once JPATH_LIBRARIES.DS.'pattemplate'.DS.'patTemplate'.DS.'Function.php';
include_once JPATH_LIBRARIES.DS.'pattemplate'.DS.'patTemplate'.DS.'Modifier.php';
include_once JPATH_LIBRARIES.DS.'pattemplate'.DS.'patTemplate.php';

include_once JPATH_LIBRARIES.DS.'phpgacl'.DS.'gacl.php';
include_once JPATH_LIBRARIES.DS.'phpgacl'.DS.'gacl_api.php';

$folders = EasyFolder::folders($basePath);
array_unshift($folders, '');//add 'base folder'
$folders[] = 'xxxxx';//for custom class list

$JMethods = array();

for ($i = 0; $i < count($folders); $i++)
{
	#var_dump($files);
	if( $folders[$i] == 'xxxxx' )
	{
		$files = array('xxxxx');
	}
	else
	{
		$p = ($folders[$i]) ? $basePath.DS.$folders[$i] : $basePath;
		if( $folders[$i])
		{
			$files = EasyFolder::files($p, 'php', true, true, $basePath);

		}
		else
		{
			$files = EasyFolder::files($p, 'php', false, true, $basePath);
		}
	}
	foreach ($files as $file)
	{
		echo '<hr />FILE: '.str_replace($basePath.DS, '', $file).BR;
		if($file == 'xxxxx')
		{
			//--custom class list - files included before
			$foundClasses = array('JObject', 'JObservable', 'JObserver', 'JDocumentRenderer', 'JRequest', 'JEvent', 'JRegistry', 'JVersion');//, 'JController', 'JComponentHelper', 'JModel');
		}
		else
		{
			$allClasses = get_declared_classes();
			if( ! $allClasses )
			{
				$allClasses = array();
			}
			if( strpos($file, 'import.php')){echo 'abort'.BR; continue;}
			include_once $file;
			$foundClasses = array_diff(get_declared_classes(), $allClasses);

			//--Exeptions from the rules..
			if( ! count($foundClasses))
			{
				$fileName = $file;
				if($file == 'methods.php')
				{
					$foundClasses = array('JRoute', 'JText');
				}

				if( ! count($foundClasses))
				{
					echo sprintf('<h3>no classes found in -- %s</h3>',str_replace($basePath.DS, '', $file));
				}
			}
		}

		foreach ($foundClasses as $c)
		{
			echo '<span style="background-color: yellow;">CLASS: '.$c.'</span>'.BR;
			$class = new ReflectionClass($c);

			$methods = $class->getMethods();
			foreach ($methods as $method)
			{
				$rr = $method->getDeclaringClass();
				if( $method->getDeclaringClass()->getName() != $c ) { continue; }
				echo $method->name.BR;

				$m = new stdClass();
				$m->class = $c;
				$m->name = $method->name;
				$s =( $file == 'xxxxx' ) ? $method->getFileName() : $file;
				$m->file = str_replace($basePath.DS, '', $s);
				$m->start = $method->getStartLine();
				$m->end = $method->getEndLine();

				$JMethods[] = $m;
			}//foreach
		}//foreach
	}//foreach
}//for

$mStrings = array();

foreach ($JMethods as $m)
{
	$mStrings[] = $m->class.'#'.$m->name.'#'.$m->file.'#'.$m->start.'#'.$m->end;
}

$s = implode(NL, $mStrings);
$version = new JVersion();
$v = str_replace('.', '_', $version->getShortVersion());
$fName = 'jmethodlist_'.$v.'.txt';
echo $fName.BR;
if( ! file_put_contents($fName, $s))
{
	echo '<h1 style="color: red;">Unable to write file </h1>';
}
else
{
	echo '<h1 style="color: green;">Finished <tt>=;)</tt></h1>';
	echo sprintf('Written to: %s',$fName).BR;
	echo sprintf('%s methods found', count($JMethods)).BR;
}

######################################
## helpers..
######################################

function jimport()
{
	;
}//function

class JLoader
{
	function register()
	{
		;
	}//function

	function import()
	{
		;
	}//function
}//class

class EasyFolder
{
	/**
	 * Utility function to read the files in a folder.
	 *
	 * @param	string	The path of the folder to read.
	 * @param	string	A filter for file names.
	 * @param	mixed	True to recursively search into sub-folders, or an
	 * integer to specify the maximum depth.
	 * @param	boolean	True to return the full path to the file.
	 * @param	array	Array with names of files which should not be shown in
	 * the result.
	 * @return	array	Files in the given folder.
	 * @since 1.5
	 */
	function files($path, $filter = '.', $recurse = false, $fullpath = false, $stripPath = '', $exclude = array('.svn', 'CVS'))
	{
		// Initialize variables
		$arr = array();

		// Check to make sure the path valid and clean
		#		$path = JPath::clean($path);

		// Is the path a folder?
		if (!is_dir($path)) {
			echo 'EasyFolder::files: Path is not a folder: ' . $path;
			return false;
		}

		// read the source directory
		$handle = opendir($path);
		while (($file = readdir($handle)) !== false)
		{
			if (($file != '.') && ($file != '..') && (!in_array($file, $exclude))) {
				$dir = $path . DS . $file;
				$isDir = is_dir($dir);
				if ($isDir) {
					if ($recurse) {
						if (is_integer($recurse)) {
							$arr2 = EasyFolder::files($dir, $filter, $recurse - 1, $fullpath);
						} else {
							$arr2 = EasyFolder::files($dir, $filter, $recurse, $fullpath);
						}

						$arr = array_merge($arr, $arr2);
					}
				} else {
					if (preg_match("/$filter/", $file)) {
						if ($fullpath) {

							$arr[] = $path.DS.$file;
						} else {
							$arr[] = $file;
						}
					}
				}
			}
		}
		closedir($handle);

		asort($arr);
		return $arr;
	}//function

	/**
	 * Utility function to read the folders in a folder.
	 *
	 * @param	string	The path of the folder to read.
	 * @param	string	A filter for folder names.
	 * @param	mixed	True to recursively search into sub-folders, or an
	 * integer to specify the maximum depth.
	 * @param	boolean	True to return the full path to the folders.
	 * @param	array	Array with names of folders which should not be shown in
	 * the result.
	 * @return	array	Folders in the given folder.
	 * @since 1.5
	 */
	function folders($path, $filter = '.', $recurse = false, $fullpath = false, $exclude = array('.svn', 'CVS'))
	{
		// Initialize variables
		$arr = array();

		// Check to make sure the path valid and clean
		#		$path = JPath::clean($path);

		// Is the path a folder?
		if (!is_dir($path)) {
			JError::raiseWarning(21, 'JFolder::folder: ' . JText::_('Path is not a folder'), 'Path: ' . $path);
			return false;
		}

		// read the source directory
		$handle = opendir($path);
		while (($file = readdir($handle)) !== false)
		{
			if (($file != '.') && ($file != '..') && (!in_array($file, $exclude))) {
				$dir = $path . DS . $file;
				$isDir = is_dir($dir);
				if ($isDir) {
					// Removes filtered directories
					if (preg_match("/$filter/", $file)) {
						if ($fullpath) {
							$arr[] = $dir;
						} else {
							$arr[] = $file;
						}
					}
					if ($recurse) {
						if (is_integer($recurse)) {
							$arr2 = JFolder::folders($dir, $filter, $recurse - 1, $fullpath);
						} else {
							$arr2 = JFolder::folders($dir, $filter, $recurse, $fullpath);
						}

						$arr = array_merge($arr, $arr2);
					}
				}
			}
		}
		closedir($handle);

		asort($arr);
		return $arr;
	}//function

}//class
